/**
 * 
 */
package pruebas.tiendaOl.dominio.entidades;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.TableGenerator;
import javax.persistence.Transient;
import javax.persistence.Version;

import pruebas.tiendaOl.dominio.calificadores.CalEvento;
import pruebas.tiendaOl.dominio.incrustables.ItemCarrito;
import pruebas.tiendaOl.dominio.repositorios.RepoCarrito;

import com.intelap.fabricaciones.AyudaDisparoEventos;
import com.intelap.fabricaciones.Entidad;
import com.intelap.utils.DbgHlp;
import com.intelap.utils.ProductorRecursos;

/** @author ggpollit */
@Entity
@Access(AccessType.PROPERTY)
public class Carrito extends AyudaDisparoEventos implements Entidad<Carrito> {
//	private static final Logger logger = ProductorRecursos.getLogger(Carrito.class); 

	public Carrito(Cliente cliente) {
		this.cliente = cliente;
		this.items = new HashMap<>();
	}

	//// Propiedades persistentes ////
	private Cliente cliente;
	@OneToOne(mappedBy = "carrito")
	protected Cliente getCliente() {
		return cliente;
	}
	protected void setCliente(Cliente cliente) {
		this.cliente = cliente;
	}

	private Map<TipoArticulo, ItemCarrito> items;
	@ElementCollection
	protected Map<TipoArticulo, ItemCarrito> getItems() {
		return items;
	}
	protected void setItems(Map<TipoArticulo, ItemCarrito> items) {
		this.items = items;
	}

	//// Propiedades transitorias //// 
	private transient RepoCarrito repoCarrito;
	@Transient
	private RepoCarrito getRepoCarrito() {
		if (repoCarrito == null)
			this.repoCarrito = ProductorRecursos.getManagedBean(this.getBeanManager(), RepoCarrito.class);
		return this.repoCarrito;
	}


	////////////////// Comportamiento /////////////////////// 
	@Transient
	public Map<TipoArticulo, ItemCarrito> getItems_const() {
		return Collections.unmodifiableMap(this.getItems());
	}

	/** Pone en este carrito la cantidad recibida de articulos del tipo recibido. */
	public void ponerArticulos(TipoArticulo tipoArticulo, int cantidad) {
		assert cantidad > 0;
		ItemCarrito item = this.getItems().get(tipoArticulo);
		if (item == null) {
			item = this.getRepoCarrito().crearNuevoItem(cantidad);
			this.getItems().put(tipoArticulo, item);
//			this.getDelegado().lanzadorEventosItemAgregado.fire(new EventoCarrito(tipoArticulo, item, cantidad));
			this.dispararEvento(new EventoCarrito(tipoArticulo, item, cantidad), CalEvento.AGREGADO );
		} else {
			item.agregar(cantidad);
//			this.getDelegado().lanzadorEventosItemModificado.fire(new EventoCarrito(tipoArticulo, item, cantidad));
			this.dispararEvento(new EventoCarrito(tipoArticulo, item, cantidad), CalEvento.MODIFICADO );
		}
	}

	/** Intenta sacar de este carrito la cantidad recibida de articulos del tipo recibido
	 * Da la cantidad de articulos que se pudieron sacar. */
	public int sacarArticulos(TipoArticulo tipoArticulo, int cantidadSeIntentaSacar) {
		ItemCarrito item = this.getItems().get(tipoArticulo);
		if (item == null)
			return 0;
		else {
			int cantidadQuitada = item.quitar(cantidadSeIntentaSacar);
			if (item.getCantidad() == 0) {
				this.getItems().remove(tipoArticulo);
//				this.getDelegado().lanzadorEventosItemQuitado.fire(new EventoCarrito(tipoArticulo, item, -cantidadQuitada));
				this.dispararEvento(new EventoCarrito(tipoArticulo, item, -cantidadQuitada), CalEvento.QUITADO);
			} else {
//				this.getDelegado().lanzadorEventosItemModificado.fire(new EventoCarrito(tipoArticulo, item, -cantidadQuitada));
				this.dispararEvento(new EventoCarrito(tipoArticulo, item, -cantidadQuitada), CalEvento.MODIFICADO );
			}
			return cantidadQuitada;
		}
	}


	public static class EventoCarrito {
		/** Tipo de articulo cuya cantidad de unidades existentes en el carrito ha cambiado. */
		public final TipoArticulo tipoArticulo;
		/** Es positivo si se han agregado articulos a la gondola, y negativo si se han quitado. */
		public final ItemCarrito itemCarrito;
		/** Debe ser positivo si se han agregado articulos a la gondola, y negativo si se han quitado */
		public final int cantidadAgregada;
		/** @param tipoArticulo tipo de articulo cuya cantidad de unidades existentes en la góndola ha cambiado
		 * @param itemCarrito item afectado
		 * @param cantidadAgregada debe ser positivo si se han agregado articulos al carrito, y negativo si se han quitado */
		EventoCarrito(TipoArticulo tipoArticulo, ItemCarrito itemCarrito, int cantidadAgregada) {
			this.tipoArticulo = tipoArticulo;
			this.itemCarrito = itemCarrito;
			this.cantidadAgregada = cantidadAgregada;
		}
		@Override
		public String toString() {
			return DbgHlp.toString(this, "tipoArticulo", "itemCarrito", "cantidadAgregada");
		}
	}


	///////////// toString, hashCode and equals ////////////////

	@Override
	public String toString() {
		return DbgHlp.toString(this, "id", "version");
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (int) (getId() ^ (getId() >>> 32));
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof Carrito))
			return false;
		Carrito other = (Carrito) obj;
		if (getId() != other.getId())
			return false;
		return getId() != 0;
	}


	////////////////// Requerido por JPA /////////////////////// 
	protected Carrito() {}

	private long id;
	@Id
	@TableGenerator(name = "generadorIdsCarrito", table = "ULTIMOS_NUMS_SECUENCIA", pkColumnName = "NOMBRE", valueColumnName = "VALOR", pkColumnValue = "Carrito")
	@GeneratedValue(strategy = GenerationType.TABLE, generator = "generadorIdsCarrito")
	protected long getId() {
		return this.id;
	}
	protected void setId(long id) {
		this.id = id;
	}

	protected int version;
	@Version
	protected int getVersion() {
		return this.version;
	}
	protected void setVersion(int version) {
		this.version = version;
	}
}
